﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using imaginecup.util;
using Imaginecup.util.resourceMan;
using Microsoft.Xna.Framework;
using Imaginecup.sprite.changeSourceSize;

namespace Imaginecup.sprite
{
    
    public class WorldSprite : ISprite
    {
        public class DrawTextureRange
        {
            public List<Vector2> m_IndexList;
            public List<EntityInfo>  m_DrawInfoList;
            public List<Vector2> m_SrcInfoList;

            
            public DrawTextureRange()
            {
                m_DrawInfoList = new List<EntityInfo>();
                m_IndexList = new List<Vector2>();
                m_SrcInfoList = new List<Vector2>();
            }

            public void Release()
            {
                m_DrawInfoList.Clear();
                m_IndexList.Clear();
                m_SrcInfoList.Clear();
            }

            public int GetCount()
            {
                return m_DrawInfoList.Count;
            }
        }

        private List<String> m_TextureNameList;
        private List<Vector2> m_TextureSize;
        private List<Vector2> m_TextureOriginSize;
        private Vector2 m_TextureRatio;
        //텍스쳐 사이즈에 대한 처리 어떻게할지??? -> 텍스쳐 사이즈와 , 월드맵상 사이즈가 다를 경우?확대 축소때문에...

        private Vector2 m_Max;


        private ISourceInfoClass m_SourceInfo;
        
        public WorldSprite()
        {
            m_TextureNameList = new List<String>();
            m_TextureSize = new List<Vector2>();
            m_TextureOriginSize = new List<Vector2>();
        }

        public void SetMax(Vector2 max)
        {
            m_Max = max;
        }

        public void SetSourceInfoClass(ISourceInfoClass sourceClass)
        {
            m_SourceInfo = sourceClass;
        }

        // 월드사이즈/텍스쳐사이즈 = Ratio -> 월드사이즈 = 텍스쳐사이즈 * Ratio  ( ratio를 이용하여 텍스쳐 좌표를 월드 좌표로 변환)
        public void AddTextureName(String name)
        {
            m_TextureNameList.Add(name);

            ResourceMan resource = ResourceMan.GetResourceMan();
            Vector2 textureSize = resource.GetFrameSize(name);

            m_TextureOriginSize.Add(textureSize);
            m_TextureSize.Add(textureSize);
        }

        private void ChangeTextureSize()
        {
            for(int i = 0 ; i < m_TextureSize.Count; i++ )
            {
                m_TextureSize[i] = m_TextureOriginSize[i] * m_TextureRatio; 
            }
        }

        public DrawTextureRange GetRange(EntityInfo srcInfo , EntityInfo destInfo)
        {     
            int WorldY = 0;
            int WorldX = 0;
            
            ResourceMan resource = ResourceMan.GetResourceMan();

            Texture2D texture = null;

            Vector2 WorldSize = new Vector2();

            for( int y = 0 ; y < m_Max.Y; y++ )
            {
                WorldX = 0;
                WorldSize.Y = m_TextureSize[y * (int)m_Max.X + 0].Y;

                int BottomPosition = WorldY + (int)WorldSize.Y;

                for( int x = 0 ; x < m_Max.X; x++ )
                {
                   texture = resource.GetTexture( m_TextureNameList[ y * (int)m_Max.X + x ] );
                   WorldSize.X = m_TextureSize[y * (int)m_Max.X + x].X;

                   int RightPosition = WorldX + (int)WorldSize.X;

                   if( WorldX <= srcInfo.mPosition.X && srcInfo.mPosition.X < RightPosition &&
                       WorldY <= srcInfo.mPosition.Y && srcInfo.mPosition.Y < BottomPosition)
                   {
                       //현재 소스인덱스를 구함.
                       EntityInfo info = new EntityInfo(srcInfo.mPosition.X - WorldX, srcInfo.mPosition.Y - WorldY, srcInfo.mSize.X, srcInfo.mSize.Y);
                       return SetDrawInfoList(new Vector2(x , y), info, RightPosition, BottomPosition, destInfo);
                   }

                   
                    WorldX = RightPosition;
                }
                WorldY += (int)WorldSize.Y;
            }

            return null;
        }


        private DrawTextureRange SetDrawInfoList(Vector2 index , EntityInfo srcInfo, int RightPosition, int BottomPosition , EntityInfo destInfo)
        {
            int MarginX = RightPosition - (int)srcInfo.mPosition.X;
            int MarginY = BottomPosition - (int)srcInfo.mPosition.Y;

            //좌상단 지점을 구한다.
            destInfo = GetStartDrawInfo(destInfo, MarginX, MarginY);

            return GetDrawRange(index, srcInfo, destInfo, MarginX, MarginY);            
        }
        private EntityInfo GetStartDrawInfo(EntityInfo drawInfo, int MarginX, int MarginY)
        {
            if (MarginX < drawInfo.mSize.X)
            {
                drawInfo.mSize.X = MarginX;
            }

            if (MarginY < drawInfo.mSize.Y)
            {
                drawInfo.mSize.Y = MarginY;
            }
            return drawInfo;
        }

        private DrawTextureRange GetDrawRange(Vector2 index , EntityInfo srcInfo , EntityInfo destInfo , int MarginX , int MarginY)
        {
            DrawTextureRange range = new DrawTextureRange();

            SetSizeRange(range, index,
                (int)destInfo.mPosition.X, (int)destInfo.mPosition.Y,
                (int)srcInfo.mPosition.X, (int)srcInfo.mPosition.Y,
                (int)destInfo.mSize.X, (int)destInfo.mSize.Y);

            //x축 방향 남은 부분 그릴 영역 구함.
            if (MarginX < srcInfo.mSize.X)
            {
                int newWorldX = (int)(destInfo.mPosition.X + destInfo.mSize.X);

                Vector2 newIndex = index;
                newIndex.X += 1;

                SetSizeRange(range, newIndex,
                    newWorldX, (int)destInfo.mPosition.Y, 
                    0 ,  (int)srcInfo.mPosition.Y,
                    (int)srcInfo.mSize.X - MarginX, (int)destInfo.mSize.Y);
            }

            //Y축 방향의 남은 부분 그릴 영역 구함
            if (MarginY < srcInfo.mSize.Y)
            {
                int newWorldX = (int)(destInfo.mPosition.Y + destInfo.mSize.Y);

                Vector2 newIndex = index;
                newIndex.Y += 1;

                SetSizeRange(range, newIndex,
                    (int)destInfo.mPosition.X, newWorldX,
                    (int)srcInfo.mPosition.X,  0,
                    (int)destInfo.mSize.X, (int)srcInfo.mSize.Y - MarginY);
            }
            // 대각방향의 그릴 영역 구함
            if (MarginX < srcInfo.mSize.X &&
                MarginY < srcInfo.mSize.Y)
            {
                int newWorldX = (int)(destInfo.mPosition.X + destInfo.mSize.X);
                int newWorldY = (int)(destInfo.mPosition.Y + destInfo.mSize.Y);

                Vector2 newIndex = index;
                newIndex.Y += 1;
                newIndex.X += 1;

                SetSizeRange(range, newIndex,
                    newWorldX, newWorldY, 
                    0, 0,
                    (int)srcInfo.mSize.X - MarginX, (int)srcInfo.mSize.Y - MarginY);
            }

            return range;
        }
       

        private void SetSizeRange(DrawTextureRange range, Vector2 index , int X , int Y , int srcX , int srcY , int OverflowSizeX , int OverflowSizeY)
        {
            EntityInfo info = new EntityInfo(X, Y, OverflowSizeX, OverflowSizeY);
            Vector2 srcInfo = new Vector2(srcX, srcY);

            range.m_IndexList.Add(index);
            range.m_SrcInfoList.Add(srcInfo);
            range.m_DrawInfoList.Add(info);

        }

        public void Draw(SpriteBatch spriteBatch, EntityInfo entityInfo)
        {
            EntityInfo sourceInfo = m_SourceInfo.GetSourceInfo();

            m_TextureRatio = new Vector2(entityInfo.mSize.X / sourceInfo.mSize.X, entityInfo.mSize.Y / sourceInfo.mSize.Y);
            ChangeTextureSize();

            DrawTextureRange range = GetRange(sourceInfo, entityInfo);
            ResourceMan resource = ResourceMan.GetResourceMan();
            
            spriteBatch.Begin();
            for(int i = 0 ; i < range.GetCount(); i++)
            {
                
                Vector2 index = range.m_IndexList[i];
                int linearIndex = (int)index.Y * (int)m_Max.X + (int)index.X;

                Texture2D texture = ResourceMan.GetResourceMan().GetTexture( m_TextureNameList[linearIndex ] );

                EntityInfo drawInfo = range.m_DrawInfoList[i];
                Vector2 srcPosition = range.m_SrcInfoList[i];

                //  월드사이즈/텍스쳐사이즈 = Ratio -> 월드사이즈 = 텍스쳐사이즈 * Ratio  ( ratio를 이용하여 텍스쳐 좌표를 월드 좌표로 변환)
                // 텍스쳐 사이즈 = 월드 사이즈 / Ratio

                EntityInfo srcInfo = new EntityInfo(srcPosition.X / m_TextureRatio.X, srcPosition.Y / m_TextureRatio.Y,
                                                    drawInfo.mSize.X / m_TextureRatio.X, drawInfo.mSize.Y / m_TextureRatio.Y);


                spriteBatch.Draw(texture, EntityInfo.GetRectangle(drawInfo), EntityInfo.GetRectangle(srcInfo), Color.White);


            }
            spriteBatch.End();
        }

        public void Release()
        {
            m_TextureNameList.Clear();
            m_TextureSize.Clear();
            m_TextureOriginSize.Clear();
        }

    }
}
